﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.Security.Permissions;
using BackendServer.Security;
using BackendServer.App_Data;
using System.Net.Mail;
using System.Data.Objects.SqlClient;

namespace BackendServer
{
    public class VoluntariadoMobile : IVoluntariadoMobile
    {
        const string MailVoluntarioAlta = "Hola {0},<br/> Al interesarte por esta oportunidad has quedado registrado en el portal de voluntariado hacesfalta.org.Tu contraseña personal es {1}. <br/><br/> Te recomendamos que <a href=\"http://www.hacesfalta.org/usuarios/edicion/\"> accedas y cambies tu contraseña y actualices tu perfil</a> para que  las ONG puedan ofrecerte lo que estás buscando.";
        const string MailVoluntatioYaInscrito = "Muchas gracias {0}, la ONG ya recibió tu interes, puedes consultar el estado de tu candidatura en <a href=\"http://www.hacesfalta.org\"> hacesfalta.org </a>";
        const string MailVoluntatioInscripcion = "Hola {0}, Ya estás inscrit@ en la oportunidad <strong>{1}</strong> de la ONG <strong>{2}</strong> <br><br> Por favor no respondas a este  mensaje que enviamos de forma automática. Si tienes alguna duda sobre la oportunidad de voluntariado ponte en contacto con nosotros. Si tienes dudas sobre el funcionamiento de hacesfalta.org contáctanos en hacesfalta@hazloposible.org <br><br>Muchas gracias<br> Equipo de hacesfalta.org";
        const string MailONG = "Te enviamos los datos de una persona que se ha interesado en tu oportunidad <strong>{0}</strong>, desde la aplicación windows phone de voluntariado <p>Datos de contacto:<p> Nombre: {1}<br> Email: {2} <br> {3} <p>Recuerda que desde tu zona privada puedes gestionar todas las candidaturas recibidas y modificar la oportunidad o darla de baja.<br>Para cualquier duda o consulta puedes contactar con nosotros desde hacesfalta.org o llamando al 91 554 90 42.<p>Muchas gracias<br> Equipo de Hacesfalta.org";
       
        /// <summary>
       /// Devulve todas las oportunidades en un radio de x Km
       /// </summary>
       /// <param name="Latitud">Latitud actual desde donde se realiza la petición</param>
       /// <param name="Longitud">Longitud actual desde donde se realiza la petición </param>
       /// <param name="radioKm">Radio en m máximo de oportunidades mostradas</param>
       /// <returns></returns>
        public List<DTO.VoluntariadoGeolocalizado> GetOportunidades(string latitud, string longitud, int radio)
        {
            try
            {
                using (voluntariadomobileEntities vme = new voluntariadomobileEntities())
                {
                    return vme.VoluntariadoGeolocalizado.Select(
                        x => new DTO.VoluntariadoGeolocalizado()
                            {
                                idOportunidad = x.idOportunidad,
                                Titulo = x.Titulo,
                                Barrio = x.Barrio,
                                Descripcion = x.Descripcion,
                                Email = x.Email,
                                Localidad = x.Localidad,
                                Provincia = x.Provincia,
                                Lat =  x.Lat,
                                Lon = x.Lon, 
                                Ong = x.Ong,
                                OngObjetivo = x.OngObjetivo, 
                                Perfil = x.Perfil
                            }
                            ).AsEnumerable().Where(x => getDistanceM(double.Parse(x.Lat), double.Parse(x.Lon), double.Parse(latitud), double.Parse(longitud)) <= radio).ToList();
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// Devulve todas las oportunidades en un radio de x Km
        /// </summary>
        /// <param name="Latitud">Latitud actual desde donde se realiza la petición</param>
        /// <param name="Longitud">Longitud actual desde donde se realiza la petición </param>
        /// <param name="radioKm">Radio en m máximo de oportunidades mostradas</param>
        /// <returns></returns>
        public List<DTO.VoluntariadoGeolocalizado> GetOportunidadesBuscar(string busqueda)
        {
            try
            {
                using (voluntariadomobileEntities vme = new voluntariadomobileEntities())
                {
                    return vme.VoluntariadoGeolocalizado.Select(
                        x => new DTO.VoluntariadoGeolocalizado()
                        {
                            idOportunidad = x.idOportunidad,
                            Titulo = x.Titulo,
                            Barrio = x.Barrio,
                            Descripcion = x.Descripcion,
                            Email = x.Email,
                            Localidad = x.Localidad,
                            Provincia = x.Provincia,
                            Lat = x.Lat,
                            Lon = x.Lon,
                            Ong = x.Ong,
                            OngObjetivo = x.OngObjetivo,
                            Perfil = x.Perfil
                        }
                            ).Where(x => x.Provincia.Contains(busqueda) 
                                || x.Localidad.Contains(busqueda) 
                                || x.Titulo.Contains(busqueda) 
                                || x.Descripcion.Contains(busqueda)).ToList();
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
       
       /// <summary>
       /// Subscribe a un usuario en una oportunidad, lo da de alta si es necesario y avisa a la ONG de la subscripción realizada
       /// </summary>
       /// <param name="idOportunidad">Identificador de la oportunidad a la que se subscribe, es un entero, se hace un cast interno</param>
       /// <param name="nombre">Nombre del voluntario</param>
       /// <param name="apellidos">Apellidos del voluntario</param>
       /// <param name="email">email del voluntario</param>
       /// <param name="motivaciones">Motivaciones extra del voluntario</param>
       /// <returns>Devulve: -1 - error, 0 - subscripcion creada, 1 - usuario añadido y subscripción creada, 2- subcripción y usarios ya existentes en la app</returns>
       public int AddUsuarioOportunidad(int idOportunidad, string nombre, string apellidos, string email, string motivaciones)
       {
           try
           {
               using (voluntariadomobileEntities vme = new voluntariadomobileEntities())
               {
                   int result = 0;
                   //Buscamos si existe ya el usuario
                   var existsUsers = from up in vme.Ch_UsuarioPortal 
                                     join uphf in vme.Ch_UsuarioPortal_HF on up.IdUsuarioPortal equals uphf.IdUsuarioPortal
                                     join u in vme.Ch_Usuario on up.IdUsuario equals u.IdUsuario
                                     where u.Email == email && up.IdPortal == 1
                                     select up.IdUsuarioPortal;

                   int existsUser = 0;
                   //Si no existe lo damos de alta
                   if (existsUsers.Count() == 0)
                   {
                       Ch_Usuario user = new Ch_Usuario() { Email = email, FechaInsercion = DateTime.Now };
                       vme.Ch_Usuario.AddObject(user);
                       vme.SaveChanges();
                       Ch_UsuarioPortal userPortal = new Ch_UsuarioPortal() { IdUsuario = user.IdUsuario, Nombre = nombre, Apellidos = apellidos, IdPortal = 1, Password = "Passw0rd", CreationDate = DateTime.Now, LastActivityDate = DateTime.Now, LastPasswordChangedDate = DateTime.Now, UserName = nombre, EsMiembroFundacion = false, IdEstado = 2, MostrarNick = true };
                       vme.Ch_UsuarioPortal.AddObject(userPortal);
                       vme.SaveChanges();
                       Ch_UsuarioPortal_HF userPortalHF = new Ch_UsuarioPortal_HF() { IdUsuarioPortal = userPortal.IdUsuarioPortal, MostrarRangoEdad = false, EsVoluntario = true, Motivaciones = motivaciones, NumeroAportaciones = 0, EsRemunerado = false, DisponibilidadCambioResidencia = false, DisponibilidadViajar = false, CarnetConducir = false, EsUsuarioBasico = true, OrigenMobile = true };
                       vme.Ch_UsuarioPortal_HF.AddObject(userPortalHF);
                       vme.SaveChanges();
                       //Enviamos el mail de alta correspondiente
                       SendEmail(MailVoluntarioAlta, email, nombre, userPortal.Password);
                       existsUser = userPortal.IdUsuarioPortal;
                       result = 1;
                   }
                   else 
                       existsUser = existsUsers.First();
                   //Miramos si ya se registro en el aoportunidas
                   if (vme.Ch_OportunidadUsuarioPortalRel.Count(o => o.IdOportunidad == idOportunidad && o.IdUsuarioPortal == existsUser) == 0)
                   {
                       //Si no lo hizo lo registramos en la oportunidad
                       vme.Ch_OportunidadUsuarioPortalRel.AddObject(new Ch_OportunidadUsuarioPortalRel() { IdOportunidad = idOportunidad, IdUsuarioPortal = existsUser, IdEstado = 1, FechaInsercion = DateTime.Now });
                       vme.SaveChanges();
                       var oportunidad = vme.VoluntariadoGeolocalizado.SingleOrDefault(o => o.idOportunidad == idOportunidad);
                       //enviamos mail al usuario
                       SendEmail(MailVoluntatioInscripcion, email, nombre, oportunidad.Titulo, oportunidad.Ong);
                       //enviamos mail a la ong
                       SendEmail(MailONG,oportunidad.Email, oportunidad.Titulo, nombre, email);
                   }
                   else
                   {
                       //Si ya lo hizo enviamos mail de recordatorio
                       SendEmail(MailVoluntatioYaInscrito, email, nombre);
                       result = 2;
                   }
                   
                   return result;
               }
           }
           catch (Exception ex)
           {
               return -1;
           }
       }

       private void SendEmail(string body,string mailTo, params string[] parametrosMail)
       {
           MailMessage mail = new MailMessage(Settings.Default.MailFrom, mailTo);
           mail.Subject = Settings.Default.MailSubject;

           mail.Body = string.Format(body,parametrosMail);
           mail.BodyEncoding = System.Text.Encoding.UTF8;
           mail.IsBodyHtml = false;

           SmtpClient smtp = new SmtpClient(Settings.Default.MailHost, Settings.Default.MailPort);
           smtp.Credentials = new System.Net.NetworkCredential(Settings.Default.MailUser, Settings.Default.MailPassword);

           smtp.Send(mail);
       }

        /// <summary>
        /// Metodo que devuleve la distancia entre dos posiciones dadas
        /// </summary>
        /// <param name="Latitude1"></param>
        /// <param name="Longitude1"></param>
        /// <param name="Latitude2"></param>
        /// <param name="Longitude2"></param>
        /// <returns>Distancia en Metros entre dos posiciones</returns>
       protected double getDistanceM(double Latitude1, double Longitude1, double Latitude2, double Longitude2)
       {
           //Usando formula de Haversine y considerando el radio de la tierra el ecuatorial 6378Km
           int EarthRadious = 6378 * 1000;
           double DifLatRadians = (Latitude1 - Latitude2) * (Math.PI / 180);
           double DifLongRadians = (Longitude1 - Longitude2) * (Math.PI / 180);

           var a = Math.Pow(Math.Sin(DifLatRadians / 2), 2)
                   +
                   Math.Cos(Latitude1 * (Math.PI / 180))
                   *
                   Math.Cos(Latitude2 * (Math.PI / 180))
                   *
                   Math.Pow(Math.Sin(DifLongRadians / 2), 2);

           var b = 1 - a;
           var c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(b));

           return EarthRadious * c;
       }
 
    }
}
